package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"log"
	"sync"

	"golang.org/x/crypto/ssh"
)

type Host struct {
	IP   string
	User string
}

func main() {
	hosts := []Host{
		Host{"47.95.203.124", "user1"},
		// add more hosts here
	}

	cmd := "ls -la"
	key, err := ioutil.ReadFile("/opt/rsa/private.txt")
	if err != nil {
		log.Fatalf("unable to read private key: %v", err)
	}

	signer, err := ssh.ParsePrivateKey(key)
	if err != nil {
		log.Fatalf("unable to parse private key: %v", err)
	}

	config := &ssh.ClientConfig{
		User: "username",
		Auth: []ssh.AuthMethod{
			ssh.PublicKeys(signer),
		},
		HostKeyCallback: ssh.InsecureIgnoreHostKey(),
	}

	var wg sync.WaitGroup
	output := make(chan string)

	for _, host := range hosts {
		wg.Add(1)
		go func(h Host) {
			defer wg.Done()

			conn, err := ssh.Dial("tcp", h.IP+":22", config)
			if err != nil {
				log.Fatalf("unable to connect: %v", err)
			}
			defer conn.Close()

			session, err := conn.NewSession()
			if err != nil {
				log.Fatalf("unable to create session: %v", err)
			}
			defer session.Close()

			var stdoutBuf bytes.Buffer
			session.Stdout = &stdoutBuf

			err = session.Run(cmd)
			if err != nil {
				log.Fatalf("unable to run command: %v", err)
			}

			output <- fmt.Sprintf("%s %s:\n%s\n", h.IP, h.User, stdoutBuf.String())
		}(host)
	}

	go func() {
		for res := range output {
			fmt.Println(res)
		}
	}()

	wg.Wait()
	close(output)
}
